package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	logger "github.com/sirupsen/logrus"
)

var apikey string = "https://oapi.dingtalk.com/robot/send?access_token=6c6a0abe58731312c617b43237ea5ca1fc288a121a7666cbdf559e211e598333"

type DingHook struct {
	ApiUrl    string
	Leves     []logger.Level
	AtMobiles []string    // @谁
	AppName   string      // 模块前缀
	JobChan   chan []byte // 异步消息队列
	CloseChan chan bool   // 主进程关闭消息通道
}

/*
{
    "at": {
        "atMobiles":[
            "180xxxxxx"
        ],
        "atUserIds":[
            "user123"
        ],
        "isAtAll": false
    },
    "text": {
        "content":"我就是我, @XXX 是不一样的烟火"
    },
    "msgtype":"text"
}
*/

// 构造发送给钉钉的格式
type DingMsg struct {
	Msgtype string `json:"msgtype"`
	At      struct {
		AtMobiles []string `json:"atMobiles"`
	} `json:"at"`
	Text struct {
		Context string `json:"content"`
	} `json:"text"`
}

// 实现Levels 和 Fire两个方法就可以实现 hook接口

// 代表哪几个级别可以应用
func (d *DingHook) Levels() []logger.Level {
	return d.Leves
}

// 调用hook逻辑
func (d *DingHook) Fire(e *logger.Entry) error {
	msg, _ := e.String()
	d.DirectSend(msg)
	return nil
}

// 直接发消息
func (d *DingHook) DirectSend(msg string) {

	dm := DingMsg{Msgtype: "text"}
	dm.At.AtMobiles = d.AtMobiles
	dm.Text.Context = fmt.Sprintf("[日志告警log]\n[app:%s]\n"+
		"[日志详情:%s]", d.AppName, msg)
	bs, err := json.Marshal(dm)
	if err != nil {
		logger.Error("消息json.Marshal 失败[error:%v][msg:%v]", err, msg)
		return
	}
	d.JobChan <- bs
	go func() {

		// fmt.Println(dm)
		v, ok := <-d.JobChan
		if ok {
			res, err := http.Post(d.ApiUrl, "application/json", bytes.NewBuffer(v))
			if err != nil {
				logger.Error("消息发送 失败[error:%v][msg:%v]", err, msg)
			}
			if res != nil && res.StatusCode != 200 {
				logger.Error("钉钉返回错误 [StatusCode:%v][msg:%v]", res.StatusCode, msg)
			}

			body, _ := ioutil.ReadAll(res.Body)
			logger.Info(string(body))
			ret := struct {
				errcode int
				errmsg  string
			}{}
			err = json.Unmarshal(body, &ret)
			fmt.Println()

			if err != nil {
				logger.Error("钉钉返回解析错误 失败[error:%v][msg:%v]", err, msg)
			}

			if ret.errcode == 0 {
				d.CloseChan <- true
			} else {
				d.CloseChan <- false
			}
		}
	}()
}

func main() {
	logger.SetOutput(os.Stdout)
	dh := &DingHook{
		ApiUrl:    apikey,
		Leves:     []logger.Level{logger.ErrorLevel},
		AtMobiles: []string{"15157157150"},
		AppName:   "SDWAN",
		JobChan:   make(chan []byte, 1), // 初始化任务channel
		CloseChan: make(chan bool, 1),   // 初始化关闭主进程channel
	}

	// 取消掉其他默认的的格式，防止钉钉不能阅读
	logger.SetFormatter(&logger.JSONFormatter{

		TimestampFormat: "2006-01-02 15:04:05",
	})
	// dh.DirectSend("发送试试")
	logger.AddHook(dh)
	logger.Error("这是一个logger error hook 第一条")
	logger.Error("这是一个logger error hook 第二条")
	logger.Error("这是一个logger error hook 第三条")
	logger.Warn("这是一个logger Warn log") // 应该不会打

	// 阻塞主进程
	for ok := range dh.CloseChan {
		fmt.Println(ok)
	}

}
